package com.fingard.xml;

import com.fingard.text.StringHelper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Stack;

public class XmlTextReader {

    int offSet = -1;
    StringBuilder sbXml;

    //position
    //int posInLine = -1;
    //int line = -1;
    private Stack<String> stackTag = null;

    public XmlTextReader(StringBuilder p_sb) {
        sbXml = p_sb;
    }

    public XmlTextReader(String p_strXml) {
        sbXml = new StringBuilder();
        sbXml.append(p_strXml);
    }

    /**
     * 返回原始字符串
     */
    public String getOriXmlString() {
        return sbXml.toString();
    }

    XmlReadMode readMode;

    public void resetReadMode(XmlReadMode mode) {
        readMode = mode;
        offSet = 0;
        //line = 1;
        //posInLine = 1;
        stackTag = new Stack<String>();
        if (readMode == XmlReadMode.JustInnerText) {
            hashMapInnerText = new HashMap<String, ArrayList<String[]>>();
            hashMapSimple = null;
        } else if (readMode == XmlReadMode.SimpleInnerText) {
            hashMapInnerText = null;
            hashMapSimple = new HashMap<String, String[]>();
        } else {
            hashMapInnerText = null;
            hashMapSimple = null;
        }

        readedXElement = null;
    }

    /**
     * 获取当前节点路径/xx/xx/xx
     */
    private String getCurrentPath() {
        int tmpSize = stackTag.size();
        StringBuilder tmpSb = new StringBuilder();
        for (int i = 0; i < tmpSize; i++) {
            tmpSb.append("/" + stackTag.get(i));
        }
        //System.out.println("路径："+tmpSb.toString());
        return tmpSb.toString();
    }

    /**
     * 获取当前节点父路径/xx/xx/xx
     */
    private String getCurrParentPath() {
        int tmpSize = stackTag.size();
        StringBuilder tmpSb = new StringBuilder();
        for (int i = 0; i < tmpSize - 1; i++) {
            tmpSb.append("/" + stackTag.get(i));
        }
        //System.out.println("路径："+tmpSb.toString());
        return tmpSb.toString();
    }

    //String[0]存innerText，String[1]标识该节点是否已经读完，1标识已读完
    private HashMap<String, ArrayList<String[]>> hashMapInnerText;

    /**
     * 读取InnerText，读取的缓存到HashMap
     */
    public void printHashMapInnerText() {
        if (hashMapInnerText != null) {
            Iterator<String> iter = hashMapInnerText.keySet().iterator();
            //Iterator<Entry<String,ArrayList<StringBuilder>>> iter = hashMapInnerText.entrySet().iterator();
            while (iter.hasNext()) {
                String eachKey = iter.next();
                ArrayList<String[]> listSb = hashMapInnerText.get(eachKey);
                System.out.println(eachKey + ":");
                for (int i = 0; i < listSb.size(); i++) {
                    System.out.println(i + ":" + listSb.get(i)[0]);
                }
            }
        }
    }

    public void backToTop() {
        offSet = 0;
        stackTag = new Stack<String>();
        resetReadMode(XmlReadMode.None);
    }

    /**
     * 取第一个匹配到的节点的innerText，线程不安全
     */
    public String getFirstText(String p_nodePath) throws Exception {
        if (readMode == XmlReadMode.XElementReader) {
            throw new Exception("读取模式从XElementReader切换必须重新设置");
        } else if (readMode != XmlReadMode.JustInnerText) {
            resetReadMode(XmlReadMode.JustInnerText);
            //throw new Exception ("读取模式必须设置为XmlReadMode.JustInnerText");
        }
        if (hashMapInnerText.containsKey(p_nodePath)) {
            //ArrayList<StringBuilder> listSb = hashMapInnerText.get(p_nodePath);
            String[] values = hashMapInnerText.get(p_nodePath).get(0);
            if (values[1] == "1") {//节点已正常关闭
                return hashMapInnerText.get(p_nodePath).get(0)[0];//取第一个
            }
        }
        while (offSet < sbXml.length()) {
            String each = readNextUnit();

            boolean isCDATA = false;
            if (each.startsWith("<![CDATA[") && each.endsWith("]]>")) {//提取文本，加到最后一个StringBuilder下
                isCDATA = true;
                each = each.substring(each.indexOf("<![CDATA[") + 9, each.lastIndexOf("]]>"));
            }

            if (each.length() > 0) {

                String tmpCurrtPath = "";

                //System.out.println("读取到："+each);


                if (!isCDATA && stackTag.size() == 0 && each.length() > 1 && each.charAt(1) == '?') {
                    if (each.length() - 2 < 1 || each.charAt(each.length() - 2) != '?') {
                        throw new Exception("xml声明必须以?结尾");
                    }
                } else if (!isCDATA && each.charAt(0) == '<') {//<1>|<2>aaa|</2>|</1>
                    if (each.length() <= 2 || each.charAt(each.length() - 1) != '>') {
                        throw new Exception("存在问题标签：" + each);
                    } else if (each.charAt(1) == '/') {//是闭合标签
                        tmpCurrtPath = getCurrentPath();
                        String closedTag = each.substring(2, each.length() - 1);
                        if (stackTag.size() > 0) {
                            if (stackTag.pop().equals(closedTag)) {
                                ArrayList<String[]> listValues = hashMapInnerText.get(tmpCurrtPath);
                                String[] strCurrt = listValues.get(listValues.size() - 1);
                                strCurrt[1] = "1";//打上标签关闭标志

                                if (tmpCurrtPath.equals(p_nodePath)) {
                                    if (hashMapInnerText.get(p_nodePath).get(0)[1] == "1") {
                                        return hashMapInnerText.get(p_nodePath).get(0)[0];
                                    } else {
                                        throw new Exception("标签：" + p_nodePath + "未正常闭合");
                                    }
                                }
                            } else {
                                throw new Exception("闭合标签：" + each + "无对应的开始标签");
                            }
                        } else {
                            throw new Exception("闭合标签：" + each + "无对应的开始标签");
                        }
                    } else if (each.charAt(each.length() - 2) == '/') {//自闭合的
                        int indexBlank = StringHelper.indexOfBlank(each);
                        String startTag = "";
                        if (indexBlank == 0) {
                            throw new Exception("标签：" + each + "不能以空白字符开头");
                        } else if (indexBlank < 0) {
                            startTag = each.substring(1, each.length() - 2);
                        } else {
                            startTag = each.substring(1, indexBlank);
                        }
                        stackTag.push(startTag);
                        tmpCurrtPath = getCurrentPath();

                        if (!hashMapInnerText.containsKey(tmpCurrtPath)) {
                            //System.out.println("新增标签："+startTag);
                            hashMapInnerText.put(tmpCurrtPath, new ArrayList<String[]>());
                        }
                        //System.out.println("标签："+startTag+"新增成员");
                        hashMapInnerText.get(tmpCurrtPath).add(new String[]{"", "1"});

                        stackTag.pop();
                        if (tmpCurrtPath.equals(p_nodePath)) {
                            if (hashMapInnerText.get(p_nodePath).get(0)[1] == "1") {
                                return hashMapInnerText.get(p_nodePath).get(0)[0];
                            } else {
                                throw new Exception("标签：" + p_nodePath + "未正常闭合");
                            }
                        }
                    } else if (each.startsWith("<!--")) {//<!-- -->
                        if (!each.endsWith("-->")) {
                            throw new Exception("注释必须以-->结尾");
                        }
                    } else {//提取标签名称
                        int indexBlank = StringHelper.indexOfBlank(each);
                        String startTag = "";
                        if (indexBlank == 0) {
                            throw new Exception("标签：" + each + "不能以空白字符开头");
                        } else if (indexBlank < 0) {
                            startTag = each.substring(1, each.length() - 1);
                        } else {
                            startTag = each.substring(1, indexBlank);
                        }
                        stackTag.push(startTag);
                        tmpCurrtPath = getCurrentPath();
                        if (!hashMapInnerText.containsKey(tmpCurrtPath)) {
                            //System.out.println("新增标签："+startTag);
                            hashMapInnerText.put(tmpCurrtPath, new ArrayList<String[]>());
                        }

                        //System.out.println("标签："+startTag+"新增成员");
                        hashMapInnerText.get(tmpCurrtPath).add(new String[]{"", "0"});
                    }
                } else if (stackTag.size() == 0) {
                    if (!StringHelper.isBlankStr(each)) {
                        throw new Exception("文档的顶层无效");
                    }
                } else if (isCDATA || each.trim().length() > 0) {//提取文本，加到最后一个StringBuilder下
                    tmpCurrtPath = getCurrentPath();
                    ArrayList<String[]> listStr = hashMapInnerText.get(tmpCurrtPath);
                    String[] strCurrt = listStr.get(listStr.size() - 1);
                    if (strCurrt[0].length() > 0) {
                        strCurrt[0] = strCurrt[0] + each;
                    } else {
                        strCurrt[0] = each;
                    }
                }
            }
            //throw new Exception ("第"+line+"行第位字符必须为<"+"");
        }
        if (hashMapInnerText.containsKey(p_nodePath)) {
            throw new Exception("标签：" + p_nodePath + "未正常闭合");
        } else {
            return null;
        }
    }

    public String getInnerXml(String p_nodePath) throws Exception {
        return getInnerOrOuterXml(p_nodePath, 'I');
    }

    public String getOuterXml(String p_nodePath) throws Exception {
        return getInnerOrOuterXml(p_nodePath, 'O');
    }

    private String getInnerOrOuterXml(String p_nodePath, char p_type) throws Exception {
        if (readMode == XmlReadMode.XElementReader) {
            throw new Exception("读取模式从XElementReader切换必须重新设置");
        } else if (readMode != XmlReadMode.None) {
            resetReadMode(XmlReadMode.None);
        }
        int indexStart = -1;
        int indexEnd = -1;
        while (offSet < sbXml.length()) {
            String each = readNextUnit();

            boolean isCDATA = false;
            if (each.startsWith("<![CDATA[") && each.endsWith("]]>")) {//提取文本，加到最后一个StringBuilder下
                isCDATA = true;
                each = each.substring(each.indexOf("<![CDATA[") + 9, each.lastIndexOf("]]>"));
            }

            if (each.length() > 0) {

                String tmpCurrtPath = "";
                if (!isCDATA && stackTag.size() == 0 && each.length() > 1 && each.charAt(1) == '?') {
                    if (each.length() - 2 < 1 || each.charAt(each.length() - 2) != '?') {
                        throw new Exception("xml声明必须以?结尾");
                    }
                } else if (!isCDATA && each.charAt(0) == '<') {//<1>|<2>aaa|</2>|</1>
                    if (each.length() <= 2 || each.charAt(each.length() - 1) != '>') {
                        throw new Exception("存在问题标签：" + each);
                    } else if (each.charAt(1) == '/') {//是闭合标签
                        tmpCurrtPath = getCurrentPath();
                        String closedTag = each.substring(2, each.length() - 1);
                        if (stackTag.size() > 0) {
                            if (stackTag.pop().equals(closedTag)) {
                                if (tmpCurrtPath.equals(p_nodePath)) {
                                    if (p_type == 'I') {
                                        indexEnd = offSet - each.length();
                                    } else {
                                        indexEnd = offSet;
                                    }
                                    return sbXml.substring(indexStart, indexEnd);
                                }
                            } else {
                                throw new Exception("闭合标签：" + each + "无对应的开始标签");
                            }
                        } else {
                            throw new Exception("闭合标签：" + each + "无对应的开始标签");
                        }
                    } else if (each.charAt(each.length() - 2) == '/') {//自闭合的
                        int indexBlank = StringHelper.indexOfBlank(each);
                        String startTag = "";
                        if (indexBlank == 0) {
                            throw new Exception("标签：" + each + "不能以空白字符开头");
                        } else if (indexBlank < 0) {
                            startTag = each.substring(1, each.length() - 2);
                        } else {
                            startTag = each.substring(1, indexBlank);
                        }
                        stackTag.push(startTag);
                        tmpCurrtPath = getCurrentPath();

                        stackTag.pop();
                        if (tmpCurrtPath.equals(p_nodePath)) {
                            if (p_type == 'I') {
                                return "";
                            } else {
                                return each;
                            }
                        }
                    } else if (each.startsWith("<!--")) {//<!-- -->
                        if (!each.endsWith("-->")) {
                            throw new Exception("注释必须以-->结尾");
                        }
                    } else {//提取标签名称
                        int indexBlank = StringHelper.indexOfBlank(each);
                        String startTag = "";
                        if (indexBlank == 0) {
                            throw new Exception("标签：" + each + "不能以空白字符开头");
                        } else if (indexBlank < 0) {
                            startTag = each.substring(1, each.length() - 1);
                        } else {
                            startTag = each.substring(1, indexBlank);
                        }
                        stackTag.push(startTag);
                        tmpCurrtPath = getCurrentPath();
                        if (tmpCurrtPath.equals(p_nodePath)) {
                            if (p_type == 'I') {
                                indexStart = offSet;
                            } else {
                                indexStart = offSet - each.length();
                            }
                        }
                    }
                }
            }
            //throw new Exception ("第"+line+"行第位字符必须为<"+"");
        }
        if (indexStart >= 0 && indexEnd < 0) {
            throw new Exception("标签：" + p_nodePath + "未正常闭合");
        } else {
            return null;
        }
    }

    public String getSimpleTextNotNull(String p_nodeName) throws Exception {
        String retValue = getSimpleText(p_nodeName);
        if (retValue == null) {
            return "";
        }
        return retValue;
    }

    private HashMap<String, String[]> hashMapSimple;
    
    public String getSimpleText(String p_nodeName) throws Exception {
    	return getSimpleTextByFilter(p_nodeName, "");
    }

    /**@param p_nodeName
     * @param pFilterNm 末尾节点名，为了加速提取节点，比如当ATS请求的xml过大时，可直接过滤读取多余的<DetailRecord>*/
    public String getSimpleTextByFilter(String p_nodeName , String pFilterNm) throws Exception {
        if (readMode == XmlReadMode.XElementReader) {
            throw new Exception("读取模式从XElementReader切换必须重新设置");
        } else if (readMode != XmlReadMode.SimpleInnerText) {
            resetReadMode(XmlReadMode.SimpleInnerText);
            //throw new Exception ("读取模式必须设置为XmlReadMode.SimpleInnerText");
        }
        if (hashMapSimple.containsKey(p_nodeName)) {
            if (hashMapSimple.get(p_nodeName)[1].equals("1")) {//节点已正常关闭
                return hashMapSimple.get(p_nodeName)[0];
            }
        }
        while (offSet < sbXml.length()) {
            String each = readNextUnit();

            boolean isCDATA = false;
            if (each.startsWith("<![CDATA[") && each.endsWith("]]>")) {//提取文本，加到最后一个StringBuilder下
                isCDATA = true;
                each = each.substring(each.indexOf("<![CDATA[") + 9, each.lastIndexOf("]]>"));
            }

            if (each.length() > 0) {
                if (!isCDATA && stackTag.size() == 0 && each.length() > 1 && each.charAt(1) == '?') {
                    if (each.length() - 2 < 1 || each.charAt(each.length() - 2) != '?') {
                        throw new Exception("xml声明必须以?结尾");
                    }
                } else if (!isCDATA && each.charAt(0) == '<') {//<1>|<2>aaa|</2>|</1>
                    if (each.length() <= 2 || each.charAt(each.length() - 1) != '>') {
                        throw new Exception("存在问题标签：" + each);
                    } else if (each.charAt(1) == '/') {//是闭合标签
                        String closedTag = each.substring(2, each.length() - 1);
                        if (stackTag.size() > 0) {
                        	String currPath = getCurrentPath();
                            if (stackTag.pop().equals(closedTag)) {
                            	if(pFilterNm.length() >0 && currPath.equals(pFilterNm)){
                            		moveOffsetByFilter(pFilterNm);
                            	}
                                hashMapSimple.get(closedTag)[1] = "1";
                                if (closedTag.equals(p_nodeName)) {
                                    if (hashMapSimple.get(p_nodeName)[1].equals("1")) {
                                        return hashMapSimple.get(p_nodeName)[0];
                                    } else {
                                        throw new Exception("标签：" + p_nodeName + "未正常闭合");
                                    }
                                }
                            } else {
                                throw new Exception("闭合标签：" + each + "无对应的开始标签");
                            }
                        } else {
                            throw new Exception("闭合标签：" + each + "无对应的开始标签");
                        }
                    } else if (each.charAt(each.length() - 2) == '/') {//自闭合的
                        int indexBlank = StringHelper.indexOfBlank(each);
                        String startTag = "";
                        if (indexBlank == 0) {
                            throw new Exception("标签：" + each + "不能以空白字符开头");
                        } else if (indexBlank < 0) {
                            startTag = each.substring(1, each.length() - 2);
                        } else {
                            startTag = each.substring(1, indexBlank);
                        }
                        stackTag.push(startTag);

                        if (!hashMapSimple.containsKey(startTag)) {
                            hashMapSimple.put(startTag, new String[]{"", "1"});
                        }
                        
                        String currPath = getCurrentPath();
                        stackTag.pop();
                        if(pFilterNm.length() >0 && currPath.equals(pFilterNm)){
                    		moveOffsetByFilter(pFilterNm);
                    	}
                        if (startTag.equals(p_nodeName)) {
                            if (hashMapSimple.get(p_nodeName)[1].equals("1")) {
                                return hashMapSimple.get(p_nodeName)[0];
                            } else {
                                throw new Exception("标签：" + p_nodeName + "未正常闭合");
                            }
                        }
                    } else if (each.startsWith("<!--")) {//<!-- -->
                        if (!each.endsWith("-->")) {
                            throw new Exception("注释必须以-->结尾");
                        }
                    } else {//提取标签名称
                        int indexBlank = StringHelper.indexOfBlank(each);
                        String startTag = "";
                        if (indexBlank == 0) {
                            throw new Exception("标签：" + each + "不能以空白字符开头");
                        } else if (indexBlank < 0) {
                            startTag = each.substring(1, each.length() - 1);
                        } else {
                            startTag = each.substring(1, indexBlank);
                        }
                        stackTag.push(startTag);
                        if (!hashMapSimple.containsKey(startTag)) {
                            //System.out.println("新增标签："+startTag);
                            hashMapSimple.put(startTag, new String[]{"", "0"});
                        }
                    }
                } else if (stackTag.size() == 0) {
                    if (!StringHelper.isBlankStr(each)) {
                        throw new Exception("文档的顶层无效");
                    }
                } else if (isCDATA || each.trim().length() > 0) {//提取文本，加到最后一个StringBuilder下
                    String tmpTag = stackTag.get(stackTag.size() - 1);
                    String[] strCurrt = hashMapSimple.get(tmpTag);
                    if (strCurrt[1].equals("0")) {
                        if (strCurrt[0].length() > 0) {
                            strCurrt[0] = strCurrt[0] + each;
                        } else {
                            strCurrt[0] = each;
                        }
                    }
                }
            }
            //throw new Exception ("第"+line+"行第位字符必须为<"+"");
        }
        if (hashMapSimple.containsKey(p_nodeName)) {
            throw new Exception("标签：" + p_nodeName + "未正常闭合");
        } else {
            return null;
        }
    }
    
    private boolean hasExecMoveByFilter = false;
    private void moveOffsetByFilter(String pFilterNm){
    	if(hasExecMoveByFilter || StringHelper.isNullOrEmpty(pFilterNm)){
    		return;
    	}
    	if(sbXml.length()<10240){//超过10K再加速
    		hasExecMoveByFilter = true;
    		return;
    	}
    	
    		hasExecMoveByFilter = true;
    		String[] nmSp = StringHelper.trimStart(pFilterNm, "/").split("/");
    		int[] idxSp = new int[nmSp.length];
    		for(int i=nmSp.length-1;i>=0;i--){
    			String chkStr = "</"+nmSp[i]+">";
    			idxSp[i] = this.sbXml.lastIndexOf(chkStr);//取得最后的关闭节点所在的位置
    		}
    		///ATSYH/TransReq/TransParam/DetailRecord
    		int emptyCount = 0;//统计结束节点之间是否都为空白字符
    		for(int i=nmSp.length-1;i>=0;i--){
    			int idx1 = idxSp[i];
    			if(idx1>0){
    				idx1+=nmSp[i].length()+3;//加上关闭节点字符本身的长度
    			}else{
    				break;
    			}
    			int idx2 = -1;
    			if(i==0){//最后一个
    				idx2 = sbXml.length();
    			}else{
    				idx2 = idxSp[i-1];
    				if(idx2<0){
    					break;
        			}
    			}
    			if(idx1 >0 && idx2>0 && idx2>=idx1){
    				if(i==0 && idx1==idx2){
    					emptyCount++;
    				}else{
	    				String pickStr = sbXml.substring(idx1, idx2);
	    				if(StringHelper.isBlankStr(pickStr)){
	    					emptyCount++;
	    				}else{
	    					break;
	    				}
    				}
    			}else{
    				break;
    			}
    		}
    		if(emptyCount == nmSp.length){
    			this.offSet = sbXml.length();
    		}
    	
    }

    public XElement readedXElement = null;

    /**
     * 读取所有子节点
     */
    public boolean readByParentPath(String p_parentPath) throws Exception {
        return readExtra(2, p_parentPath);
    }

    public boolean read(String p_nodePath) throws Exception {
        return readExtra(1, p_nodePath);
    }

    /**
     * 如果p_rdtype=2，p_nodePath为上级路径
     */
    private boolean readExtra(int p_rdtype, String paramPath) throws Exception {
        String trgParentNP = "";
        String trgFindNP = "";
        if (p_rdtype == 2) {
            trgParentNP = paramPath;//查下属节点
        } else {
            trgFindNP = paramPath;//查该节点
        }
        readedXElement = null;
        XElement currentXElement = null;

        if (readMode != XmlReadMode.XElementReader) {
            resetReadMode(XmlReadMode.XElementReader);
            //throw new Exception ("读取模式必须设置为XmlReadMode.XElementReader");
        }
        while (offSet < sbXml.length()) {
            String each = readNextUnit();

            boolean isCDATA = false;
            if (each.startsWith("<![CDATA[") && each.endsWith("]]>")) {//提取文本，加到最后一个StringBuilder下
                isCDATA = true;
                each = each.substring(each.indexOf("<![CDATA[") + 9, each.lastIndexOf("]]>"));
            }

            if (each.length() > 0) {

                String tmpCurrtPath = "";
                String parentPath = "";

                if (!isCDATA && stackTag.size() == 0 && each.length() > 1 && each.charAt(1) == '?') {
                    if (each.length() - 2 < 1 || each.charAt(each.length() - 2) != '?') {
                        throw new Exception("xml声明必须以?结尾");
                    }
                } else if (!isCDATA && each.charAt(0) == '<') {//<1>|<2>aaa|</2>|</1>
                    if (each.length() <= 2 || each.charAt(each.length() - 1) != '>') {
                        throw new Exception("存在问题标签：" + each);
                    } else if (each.charAt(1) == '/') {//是闭合标签
                        tmpCurrtPath = getCurrentPath();
                        parentPath = getCurrParentPath();
                        /**
                         * 2017-11-27 10:35:50
                         * 工行电票 B004 票据正面信息查询时,存在标签 <NextTag  ></NextTag  >情况,报文解析错误
                         * rs : 标签头读取为NextTag,没有读取空格,闭合标签读取空格
                         */
                        int indexBlank = StringHelper.indexOfBlank(each);
                        String closedTag = "";
                        if (indexBlank == -1) {
                            closedTag = each.substring(2, each.length() - 1);
                        } else {
                            closedTag = each.substring(2, indexBlank);
                        }
                        if (stackTag.size() > 0) {
                            if (stackTag.pop().equals(closedTag)) {
                                if (currentXElement != null) {
                                    currentXElement.isClosed = true;
                                    boolean isMatched = false;
                                    if (p_rdtype == 2) {
                                        if (parentPath.equals(trgParentNP) && tmpCurrtPath.equals(trgFindNP)) {
                                            isMatched = true;
                                        }
                                    } else if (tmpCurrtPath.equals(trgFindNP)) {
                                        isMatched = true;
                                    }
                                    if (isMatched) {
                                        StringBuilder tmpSbLog = new StringBuilder();
                                        if (currentXElement.isAllClosed(tmpSbLog)) {
                                            currentXElement = null;
                                            return true;
                                        } else {
                                            throw new Exception(tmpSbLog.toString());
                                        }
                                    }
                                    if (currentXElement.parentXElement == null) {
                                        throw new Exception("标签：" + each + "未找到上级");
                                    }
                                    currentXElement = currentXElement.parentXElement;
                                }
                            } else {
                                throw new Exception("闭合标签：" + each + "与对应的开始标签不一致");
                            }
                        } else {
                            throw new Exception("闭合标签：" + each + "无对应的开始标签");
                        }
                    } else if (each.charAt(each.length() - 2) == '/') {//自闭合的
                        int indexBlank = StringHelper.indexOfBlank(each);
                        String startTag = "";
                        if (indexBlank == 0) {
                            throw new Exception("标签：" + each + "不能以空白字符开头");
                        } else if (indexBlank < 0) {
                            startTag = each.substring(1, each.length() - 2);
                        } else {
                            startTag = each.substring(1, indexBlank);
                        }
                        stackTag.push(startTag);
                        tmpCurrtPath = getCurrentPath();
                        parentPath = getCurrParentPath();
                        stackTag.pop();
                        if (currentXElement != null) {//说明这些读到的都是readedXElement的子节点
                            if (tmpCurrtPath.startsWith(trgFindNP) && !tmpCurrtPath.equals(trgFindNP)) {
                                XElement childXElement = new XElement();
                                childXElement.name = startTag;
                                //childXElement.hashMapAttributes = 
                                getAttributes(each, childXElement);
                                childXElement.isClosed = true;
                                childXElement.isSelfClosed = true;
                                currentXElement.addChild(childXElement);
                            } else {
                                throw new Exception("标签：" + trgFindNP + "未正常读取完成");
                            }
                        } else if (tmpCurrtPath.equals(trgFindNP)) {
                            readedXElement = new XElement();
                            readedXElement.name = startTag;
                            //readedXElement.hashMapAttributes = getAttributes(each);
                            getAttributes(each, readedXElement);
                            readedXElement.isClosed = true;
                            return true;
                        }
                    } else if (each.startsWith("<!--")) {//<!-- -->
                        if (!each.endsWith("-->")) {
                            throw new Exception("注释必须以-->结尾");
                        }
                    } else {//提取标签名称
                        int indexBlank = StringHelper.indexOfBlank(each);
                        String startTag = "";
                        if (indexBlank == 0) {
                            throw new Exception("标签：" + each + "不能以空白字符开头");
                        } else if (indexBlank < 0) {
                            startTag = each.substring(1, each.length() - 1);
                        } else {
                            startTag = each.substring(1, indexBlank);
                        }
                        stackTag.push(startTag);
                        tmpCurrtPath = getCurrentPath();
                        parentPath = getCurrParentPath();
                        if (currentXElement != null) {//说明这些读到的都是readedXElement的子节点
                            if (tmpCurrtPath.startsWith(trgFindNP) && !tmpCurrtPath.equals(trgFindNP)) {
                                XElement childXElement = new XElement();
                                childXElement.name = startTag;
                                //childXElement.hashMapAttributes = getAttributes(each);
                                getAttributes(each, childXElement);
                                currentXElement.addChild(childXElement);
                                currentXElement = childXElement;
                            } else {
                                throw new Exception("标签：" + trgFindNP + "未正常读取完成");
                            }
                        } else {
                            boolean isMatched = false;
                            if (p_rdtype == 2) {
                                if (parentPath.equals(trgParentNP)) {
                                    isMatched = true;
                                    trgFindNP = tmpCurrtPath;
                                }
                            } else if (tmpCurrtPath.equals(trgFindNP)) {
                                isMatched = true;
                            }
                            if (isMatched) {
                                readedXElement = new XElement();
                                readedXElement.name = startTag;
                                //readedXElement.hashMapAttributes = getAttributes(each, readedXElement);
                                getAttributes(each, readedXElement);
                                currentXElement = readedXElement;
                            }
                        }
                    }
                } else if (isCDATA || each.trim().length() > 0) {//提取文本，加到最后一个StringBuilder下
                    if (currentXElement != null) {
                        if (currentXElement.innerText.length() > 0) {
                            currentXElement.innerText = currentXElement.innerText + each;
                        } else {
                            currentXElement.innerText = each;
                        }
                    }
                }
            }
            //throw new Exception ("第"+line+"行第位字符必须为<"+"");
        }
        return false;
    }

    //HashMap<String, String>
    private void getAttributes(String p_tagWithAttr, XElement pXe) throws Exception {
        //HashMap<String, String> tmpHash = null;
        int tmpIndex = StringHelper.indexOfBlank(p_tagWithAttr);
        if (tmpIndex > 0) {
            int tmpStep = 0;
            int tmpKeyIndex = -1;
            int tmpValueIndex = -1;
            String tmpKey = "";
            String tmpValue = "";
            while (tmpIndex < p_tagWithAttr.length()) {
                if (tmpStep == 0) {//过滤所有空白字符
                    if (!StringHelper.isBlank(p_tagWithAttr.charAt(tmpIndex))) {
                        if (p_tagWithAttr.charAt(tmpIndex) == '/' && tmpIndex == p_tagWithAttr.length() - 2) {
                            break;
                        } else if (p_tagWithAttr.charAt(tmpIndex) == '>' && tmpIndex == p_tagWithAttr.length() - 1) {
                            break;
                        } else {
                            tmpStep = 1;
                            tmpKeyIndex = tmpIndex;
                        }
                    }
                } else if (tmpStep == 1) {//key
                    if (p_tagWithAttr.charAt(tmpIndex) == '=') {
                        tmpStep = 2;//key 结束，value开始
                        tmpKey = p_tagWithAttr.substring(tmpKeyIndex, tmpIndex);
                    }
                } else if (tmpStep == 2) {//value
                    if (p_tagWithAttr.charAt(tmpIndex) == '"') {
                        tmpStep = 3;
                        tmpValueIndex = tmpIndex + 1;
                    } else if (!StringHelper.isBlank(p_tagWithAttr.charAt(tmpIndex))) {
                        throw new Exception("标签" + p_tagWithAttr + "的属性值格式有误，必须以双引号打头");
                    }
                } else if (tmpStep == 3) {//value
                    if (p_tagWithAttr.charAt(tmpIndex) == '"') {
                        tmpValue = p_tagWithAttr.substring(tmpValueIndex, tmpIndex);
                        /*
                        if (tmpHash == null) {
                            tmpHash = new HashMap<String, String>();
                        }
                        if (tmpHash.containsKey(tmpKey)) {
                            throw new Exception("存在重复的属性：" + tmpKey);
                        }
                        tmpHash.put(tmpKey, tmpValue);
                        */
                        pXe.addAttr(tmpKey, tmpValue);
                        tmpStep = 0;//重置
                        tmpKeyIndex = -1;
                        tmpValueIndex = -1;
                        tmpKey = "";
                        tmpValue = "";
                    }
                }
                tmpIndex++;
            }
            if (tmpStep != 0) {
                throw new Exception("标签" + p_tagWithAttr + "的格式有误");
            }
        }
        //return tmpHash;
    }

    public int countElement(String p_nodePath) throws Exception {
        resetReadMode(XmlReadMode.None);
        int retValue = 0;
        while (offSet < sbXml.length()) {
            String each = readNextUnit();

            boolean isCDATA = false;
            if (each.startsWith("<![CDATA[") && each.endsWith("]]>")) {//提取文本，加到最后一个StringBuilder下
                isCDATA = true;
                each = each.substring(each.indexOf("<![CDATA[") + 9, each.lastIndexOf("]]>"));
            }

            if (each.length() > 0) {
                String tmpCurrtPath = "";

                if (!isCDATA && stackTag.size() == 0 && each.length() > 1 && each.charAt(1) == '?') {
                } else if (!isCDATA && each.charAt(0) == '<') {//<1>|<2>aaa|</2>|</1>
                    if (each.length() <= 2 || each.charAt(each.length() - 1) != '>') {
                        throw new Exception("存在问题标签：" + each);
                    } else if (each.charAt(1) == '/') {//是闭合标签
                        tmpCurrtPath = getCurrentPath();
                        String closedTag = each.substring(2, each.length() - 1);
                        if (stackTag.size() > 0) {
                            if (stackTag.pop().equals(closedTag)) {
                                if (tmpCurrtPath.equals(p_nodePath)) {
                                    retValue++;
                                }
                            } else {
                                throw new Exception("闭合标签：" + each + "与对应的开始标签不一致");
                            }
                        } else {
                            throw new Exception("闭合标签：" + each + "无对应的开始标签");
                        }
                    } else if (each.charAt(each.length() - 2) == '/') {//自闭合的
                        int indexBlank = StringHelper.indexOfBlank(each);
                        String startTag = "";
                        if (indexBlank == 0) {
                            throw new Exception("标签：" + each + "不能以空白字符开头");
                        } else if (indexBlank < 0) {
                            startTag = each.substring(1, each.length() - 2);
                        } else {
                            startTag = each.substring(1, indexBlank);
                        }
                        stackTag.push(startTag);
                        tmpCurrtPath = getCurrentPath();
                        stackTag.pop();
                        if (tmpCurrtPath.equals(p_nodePath)) {
                            retValue++;
                        }
                    } else if (each.startsWith("<!--")) {//<!-- -->
                        if (!each.endsWith("-->")) {
                            throw new Exception("注释必须以-->结尾");
                        }
                    } else {//提取标签名称
                        int indexBlank = StringHelper.indexOfBlank(each);
                        String startTag = "";
                        if (indexBlank == 0) {
                            throw new Exception("标签：" + each + "不能以空白字符开头");
                        } else if (indexBlank < 0) {
                            startTag = each.substring(1, each.length() - 1);
                        } else {
                            startTag = each.substring(1, indexBlank);
                        }
                        stackTag.push(startTag);
                    }
                }
            }
        }
        if (stackTag.size() > 0) {
            retValue = -1;
            String tmpTag = stackTag.pop();
            resetReadMode(XmlReadMode.None);
            throw new Exception("标签：" + tmpTag + "未正常闭合");
        }
        resetReadMode(XmlReadMode.None);
        return retValue;
    }

    //读取解析单元，如果是<打头的，读取到>；如果不是<打头的，则读取到<之前
    public String readNextUnit() {
        int startIndex = offSet;
        char startCType;//< C-表示其它字符
        if (sbXml.charAt(offSet) == '<') {
            startCType = '<';
            if (sbXml.length() > offSet + 4) {//<!--
                String tmp8char = sbXml.substring(offSet, offSet + 4);
                if (tmp8char.equals("<!--")) {
                    offSet = offSet + 4;
                    while (offSet < sbXml.length()) {//-->
                        if (sbXml.length() > offSet + 3) {
                            if (sbXml.charAt(offSet) == '-' && sbXml.charAt(offSet + 1) == '-' && sbXml.charAt(offSet + 2) == '>') {
                                offSet = offSet + 3;
                                return sbXml.substring(startIndex, offSet);
                            }
                        }
                        offSet++;
                    }
                } else if (sbXml.length() > offSet + 9) {//<![CDATA[
                    tmp8char = sbXml.substring(offSet, offSet + 9);
                    if (tmp8char.equals("<![CDATA[")) {
                        offSet = offSet + 9;
                        while (offSet < sbXml.length()) {//]]>
                            if (sbXml.length() > offSet + 3) {
                                if (sbXml.charAt(offSet) == ']' && sbXml.charAt(offSet + 1) == ']' && sbXml.charAt(offSet + 2) == '>') {
                                    offSet = offSet + 3;
                                    return sbXml.substring(startIndex, offSet);
                                }
                            }
                            offSet++;
                        }
                    }
                }
            }
        } else {
            startCType = 'C';
        }
        offSet++;
        while (offSet < sbXml.length()) {

            if (startCType == '<' && sbXml.charAt(offSet) == '>') {
                return sbXml.substring(startIndex, ++offSet);
            } else if (startCType == 'C' && sbXml.charAt(offSet) == '<') {
                return sbXml.substring(startIndex, offSet);
            }
            //if(sbXml.charAt(offSet) == '\n'){//统计行数
            //	line++;
            //	posInLine = 1;
            //}
            //else{
            //	posInLine++;
            //}
            offSet++;
        }
        return sbXml.substring(startIndex, offSet);
    }

    public String getFirstTextNotNull(String p_nodePath) throws Exception {
        String firstText = getFirstText(p_nodePath);
        return null == firstText ? "" : firstText;
    }

	/*
	private void filterBlank(){
		while(offSet<sbXml.length()){
			if(isBlank(sbXml.charAt(offSet))){
				offSet++;
			}
			else{
				break;
			}
		}
	}
	*/


}
